﻿
using System;
using System.Collections.Generic;
using System.Reflection;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace GameBoxTools
{
    //区域，相同像素所占数量
    public class Area
    {
        /// <summary>
        /// 该像素位置在每张纹理中所对应的颜色
        /// </summary>
        public uint[] RT_Colors;

        /// <summary>
        /// 个数
        /// </summary>
        public uint Count;
    }

    public class MTree
    {
        List<Area> m_areas = new List<Area>();
        Node m_root = new Node();
        int count;

        class Node
        {
            public uint Value;
            public Dictionary<uint, Node> Nodes = new Dictionary<uint, Node>();
            public int Index = -1;

            public Node GetNode(uint value)
            {
                Node n;
                if (!Nodes.TryGetValue(value, out n))
                {
                    n = new Node();
                    n.Value = value;
                    Nodes.Add(value, n);
                }

                return n;
            }
        }

        private Area cache_area = null;
        private int cache_index = -1;
        private uint[] cache_rs = null;
        private Node cache_node = null;
        public Area GetArea(uint[] rs)
        {
            Node temp = null;
            this.setCount(rs.Length);
            if(!this.rsEqual(rs))
            {
                Array.Copy(rs, cache_rs, rs.Length);
                //1.找到areas index
                temp = m_root;
                foreach (var r in rs)
                {
                    temp = temp.GetNode(r);
                }

                cache_node = temp;
            }
            else
            {
                temp = cache_node;
            }

            Area area = null;

            if (temp.Index == -1)
            {
                temp.Index = m_areas.Count;
                area = new Area();

                cache_index = count;
                cache_area = area;

                uint[] rs_clone = new uint[rs.Length];
                Array.Copy(rs, rs_clone, rs.Length);
                area.RT_Colors = rs_clone;
                m_areas.Add(area);

                ++count;
            }
            else
            {
                if(temp.Index != cache_index)
                {
                    area = m_areas[temp.Index];
                    cache_area = area;
                    cache_index = temp.Index;
                }
                else
                {
                    area = cache_area;
                }
            }

            return area;
        }

        public List<Area> GetAreaList()
        {
            return m_areas;
        }

        private bool rsEqual(uint[] rs)
        {
            for(int i = 0; i < rs.Length; ++i)
            {
                if (rs[i] != this.cache_rs[i])
                    return false;
            }

            return true;
        }

        private void setCount(int count)
        {
            if(null == cache_rs || count != cache_rs.Length)
            {
                cache_rs = new uint[count];
            }
        }

        public void Reset()
        {
            cache_area = null;
            cache_index = -1;
            cache_rs = null;
            cache_node = null;
            count = 0;
            m_areas.Clear();
            ResetTree(m_root);
        }

        private void ResetTree(Node node)
        {
            if (null != node)
            {
                var nodes = node.Nodes.Values;
                foreach (var item in nodes)
                {
                    ResetTree(item);
                }

                node.Index = -1;
            }
        }

        public void Clear()
        {
            this.ClearTree(m_root);
        }

        private void ClearTree(Node node)
        {
            if (null != node)
            {
                foreach(var item in node.Nodes.Values)
                {
                    ClearTree(item);
                }

                node.Nodes.Clear();
            }
        }
    }

    public static class Util
    {
        public static int rgbaCount = 4;//颜色通道使用数量

        //进度条
        public static void ShowProgress(int total, int cur)
        {
#if UNITY_EDITOR
            float val = (float)cur / (float)total;
            EditorUtility.DisplayProgressBar("data processing", "please waiting...", val);
#endif
        }

        public static void CloseProgress()
        {
#if UNITY_EDITOR
            EditorUtility.ClearProgressBar();
#endif
        }

#if UNITY_EDITOR
        static Assembly assembly = Assembly.GetAssembly(typeof(SceneView));
        static Type logEntries = assembly.GetType("UnityEditor.LogEntries");
        static MethodInfo clearConsoleMethod = logEntries.GetMethod("Clear");
#endif
        //清除控制台信息
        public static void ClearConsole()
        {
#if UNITY_EDITOR
            clearConsoleMethod.Invoke(new object(), null);
#endif
        }

        static uint[] masks = new uint[4] { (uint)0xff << 24, (uint)0xff << 16, (uint)0xff << 8, (uint)0xff << 0 };//r,g,b,a
        /// <summary>
        /// 计算overdraw
        /// </summary>
        /// <param name="list">源数据</param>
        /// <param name="renders">对应Render列表</param>
        /// <param name="rtCount">纹理数量</param>
        /// <returns></returns>
        public static float calcOverdraw(List<Area> list, int[] renders, int rtCount)
        {
            uint[] mask = new uint[rtCount];
            foreach(var render in renders)
            {
                int index = (render % rgbaCount);//颜色索引
                int rt = render / rgbaCount;//纹理索引

                mask[rt] += masks[index];
            }

            var pixelCount = 0u;//有效像素个数

            var pixelDrawCount = 0u;//总绘制次数

            foreach (var item in list)
            {
                if (AndOpEquals0(item.RT_Colors, mask))
                    continue;

                pixelCount += item.Count;
                pixelDrawCount += (GetRCount(item.RT_Colors, mask) * item.Count);
            }

            float overdraw = 0;
            if(0 != pixelCount)
                overdraw = pixelDrawCount / (float)pixelCount;

            return overdraw;
        }

        static uint GetRCount(uint[] p, uint[] rMask)
        {
            var sum = 0u;
            for (int i = 0; i < p.Length; i++)
            {
                var t = p[i] & rMask[i];

                sum += (t >> 24) & 0xff;
                sum += (t >> 16) & 0xff;
                sum += (t >> 8) & 0xff;
                sum += (t >> 0) & 0xff;
            }
            return sum;
        }

        static bool AndOpEquals0(uint[] l, uint[] r)
        {
            for (int i = 0; i < l.Length; i++)
            {
                if ((l[i] & r[i]) != 0)
                    return false;
            }

            return true;
        }

        //高四位颜色，低四位透明
        static uint[] tmasks = new uint[4] { (uint)0xf0 << 24, (uint)0xf0 << 16, (uint)0xf0 << 8, (uint)0xf0 << 0 };//r,g,b,a
        static uint[] tamasks = new uint[4] { (uint)0x0f << 24, (uint)0x0f << 16, (uint)0x0f << 8, (uint)0x0f << 0 };//r,g,b,a
        /// <summary>
        /// 计算透明区域占比
        /// </summary>
        /// <param name="list">源数据</param>
        /// <param name="renders">对应Render列表</param>
        /// <param name="rtCount">纹理数量</param>
        /// <returns></returns>
        public static float calcTransparent(List<Area> list, int[] renders, int rtCount)
        {
            uint[] mask = new uint[rtCount];
            uint[] amask = new uint[rtCount];
            foreach (var render in renders)
            {
                int index = (render % rgbaCount);//颜色索引
                int rt = render / rgbaCount;//纹理索引

                mask[rt] += tmasks[index];
                amask[rt] += tamasks[index];
            }

            var pixelCount = 0u;//有效像素个数

            var pixelAlphaCount = 0u;//总绘制次数

            foreach (var item in list)
            {
                if (Trans_AndOpEquals0(item.RT_Colors, mask))
                    continue;

                pixelCount += item.Count;
                pixelAlphaCount += Trans_AndOpEquals0(item.RT_Colors, amask) ? 0u : item.Count;
            }

            float transrate = 0;
            if (0 != pixelCount)
                transrate = pixelAlphaCount / (float)pixelCount;

            return transrate;
        }

        static bool Trans_AndOpEquals0(uint[] l, uint[] r)
        {
            for (int i = 0; i < l.Length; i++)
            {
                if ((l[i] & r[i]) != 0)
                    return false;
            }

            return true;
        }
    }
}